package com.easylive.app.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
import android.widget.Toast;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.aliyun.utils.EncodeUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory;
import com.easylive.app.photo.PhotoPlayerActivity;
import com.easylive.app.video.NetWatchdog;
import com.easylive.app.video.VideoPlayerActivity;
import com.easylive.app.video.VideoPlayerView;

import org.apache.http.util.EncodingUtils;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.server.WebSocketServer;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MediaService extends Service {
    public static final String SERVICE_MSG_ACTION = "com.el.app.action.SERVICE_MSG";
    private static final String TAG = MediaService.class.getSimpleName();
    private static final String WS_URL = "ws://39.108.11.69:2346";
    private static final String INIT_DATA_FILE = "daolan_sid.txt";
    public static boolean isPlaying, mShouldPlay;
    public ArrayList<String> mPhotoList = new ArrayList();
    public ArrayList<String> mVideoList = new ArrayList();
    private Context mContext;
    private EventWSClient mWSClient;
    private String mPlayMode = "";
    private SharedPreferences mSharedPreferences;
    private boolean isWSSConnected;
    private Handler mHandler;

    public static String getDeviceSN() {
        String serial = null;
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class);
            serial = (String) get.invoke(c, "ro.serialno");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return serial;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(mContext!=null){
            tryToPlay();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void init() {
        Log.d(TAG, "init");
        mContext = this;
        initPhotoCachePath(this);
        mSharedPreferences = getSharedPreferences("media_cache", Context.MODE_PRIVATE);
        initMediaData();
        initEventWSS();
        initNetWatchdog();
        mHandler = new Handler(Looper.getMainLooper());
    }

    private void initMediaData() {
        Set<String> videoSet = mSharedPreferences.getStringSet("video", null);
        if (videoSet != null) {
            mVideoList.addAll(videoSet);
        }
        Set<String> photoSet = mSharedPreferences.getStringSet("photo", null);
        if (photoSet != null) {
            mPhotoList.addAll(photoSet);
        }
    }

    private void initNetWatchdog() {
        NetWatchdog mNetWatchdog = new NetWatchdog(mContext);
        mNetWatchdog.setNetChangeListener(new MyNetChangeListener());
        mNetWatchdog.setNetConnectedListener(new MyNetConnectedListener());
        mNetWatchdog.startWatch();
    }

    private void initPhotoCachePath(Context ctx) {
        String cachePath = "/data/data/" + ctx.getPackageName() + "/media/photo/";
        long cacheSize = 1024 * 1024 * 100;//100M
        File cacheFile = new File(cachePath);
        if (!cacheFile.exists()) {
            cacheFile.mkdirs();
        }
        Glide.init(ctx, new GlideBuilder().setDiskCache(new DiskLruCacheFactory(cachePath, cacheSize)));
    }

    private void initEventWSS() {
        URI uri;
        try {
            uri = new URI(WS_URL);
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return;
        }
        mWSClient = new EventWSClient(uri);
        String dataJson = readFile(INIT_DATA_FILE);
        Log.d(TAG, "initData:" + dataJson);
        Map map = JSON.parseObject(dataJson, Map.class);
        if (map != null) {
            String sn = (String) map.get("sn");
            String sid = (String) map.get("sid");
            if (TextUtils.isEmpty(sn)) {
                sn = "000-000-000";
                map.put("sn", sn);
            }
            if (TextUtils.isEmpty(sid)) {
                sid = "0";
                map.put("sid", "0");
            }
            map.put("type", "register");
            map.put("token", "Qx0tY1IjaJd8Q9t5hKzLo9cRGVM4mFDjwpflNBBXLrgfLECXzz4uWDUER1ukUEp5");
            String initMsg = JSON.toJSONString(map);
            mWSClient.setInitData(initMsg);
        }
        mWSClient.connect();
    }

    private void handleWSSMsg(String message) {
        ServerMessage msg = JSON.parseObject(message, ServerMessage.class);
        if (msg != null) {
            switch (msg.getType()) {
                case "register":
                    if (msg.getErrcode() == 0) {//注册成功
                        mWSClient.send("{\"type\":\"state\"}");
                    }
                    break;
                case "state":
                    if (msg.getErrcode() == 0) {
                        String data = msg.getData();
                        try {
                            Map map = JSON.parseObject(data, Map.class);
                            mShouldPlay = (boolean) map.get("state");
                            mSharedPreferences.edit().putBoolean("should_play", mShouldPlay).apply();
                            if (mShouldPlay) {
                                mWSClient.send("{\"type\":\"poster\"}");
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case "poster":
                    if (msg.getErrcode() == 0) {
                        String data = msg.getData();
                        try {
                            Map map = JSON.parseObject(data, Map.class);
                            JSONArray photo = (JSONArray) map.get("thumbs");
                            JSONArray video = (JSONArray) map.get("video");
                            if (!photo.isEmpty()) {
                                List<String> photoList = photo.toJavaList(String.class);
                                if (!mPhotoList.isEmpty()) {
                                    mPhotoList.clear();
                                }
                                mPhotoList.addAll(photoList);
                                photoList.clear();
                            }
                            if (!video.isEmpty()) {
                                List<String> videoList = video.toJavaList(String.class);
                                if (!mVideoList.isEmpty()) {
                                    mVideoList.clear();
                                }
                                mVideoList.addAll(videoList);
                                videoList.clear();
                            }
                            tryToPlay();
                            cacheMediaData();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case "setState":
                    String data = msg.getData();
                    try {
                        mWSClient.send("{\"type\":\"setState\",\"errcode\":0,\"message\":\"set state ok.\"}");
                        Map map = JSON.parseObject(data, Map.class);
                        mShouldPlay = (boolean) map.get("state");
                        mSharedPreferences.edit().putBoolean("should_play", mShouldPlay).apply();
                        String newPlayMode = (String) map.get("mode");
                        boolean playModeChanged = false;
                        if (!mPlayMode.equals(newPlayMode)) {
                            mPlayMode = newPlayMode;
                            playModeChanged = true;
                            mSharedPreferences.edit().putString("play_mode", mPlayMode).apply();
                        }
                        if (isPlaying) {
                            if (mShouldPlay) {
                                if (playModeChanged) {
                                    tryToPlay();
                                }
                            } else {
                                Log.d(TAG, "close media player.");
                                sendServiceMsg("all_exit");
                                isPlaying = false;
                            }
                        } else if (mShouldPlay) {
                            tryToPlay();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case "updateCache":
                    mWSClient.send("{\"type\":\"updateCache\",\"errcode\":0,\"message\":\"receive updateCache ok.\"}");
                    if (isPlaying) {//先退出播放，防止清缓存时导致播放错误
                        sendServiceMsg("all_exit");
                        isPlaying = false;
                    }
                    clearCache();
                default:
                    break;
            }

        }
    }

    private void cacheMediaData() {
        SharedPreferences.Editor editor = mSharedPreferences.edit();
        if (!mVideoList.isEmpty()) {
            Set<String> dataSet = new HashSet<>();
            dataSet.addAll(mVideoList);
            editor.putStringSet("video", dataSet);
        }
        if (!mPhotoList.isEmpty()) {
            Set<String> dataSet = new HashSet<>();
            dataSet.addAll(mPhotoList);
            editor.putStringSet("photo", dataSet);
        }
        editor.apply();
    }

    private void sendServiceMsg(String message) {
        Log.d(TAG, "service msg:" + message);
        Intent intent = new Intent(SERVICE_MSG_ACTION);
        intent.putExtra("msg", message);
        LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(intent);
    }

    private void tryToPlay() {
        mHandler.removeCallbacksAndMessages(null);
        if (!isWSSConnected) {
            mShouldPlay = mSharedPreferences.getBoolean("should_play", false);
            mPlayMode = mSharedPreferences.getString("play_mode", "");
        }
        if (mShouldPlay) {
            Intent intent = null;
            if ("video".equals(mPlayMode) && !mVideoList.isEmpty()) {
                intent = new Intent(mContext, VideoPlayerActivity.class);
                intent.putStringArrayListExtra("data", mVideoList);
                //sendServiceMsg("video_play");
            } else if ("thumb".equals(mPlayMode) && !mPhotoList.isEmpty()) {
                intent = new Intent(mContext, PhotoPlayerActivity.class);
                intent.putStringArrayListExtra("data", mPhotoList);
                //sendServiceMsg("photo_play");
            } else {
                if (!mVideoList.isEmpty()) {
                    intent = new Intent(mContext, VideoPlayerActivity.class);
                    intent.putStringArrayListExtra("data", mVideoList);
                    //sendServiceMsg("video_play");
                    mPlayMode = "video";
                } else if (!mPhotoList.isEmpty()) {
                    intent = new Intent(mContext, PhotoPlayerActivity.class);
                    intent.putStringArrayListExtra("data", mPhotoList);
                    //sendServiceMsg("photo_play");
                    mPlayMode = "thumb";
                }
            }
            if (intent != null) {
                sendServiceMsg("all_exit");
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                mContext.startActivity(intent);
                isPlaying = true;
            } else {
                new Handler(Looper.getMainLooper()).post(() -> {
                    Toast.makeText(mContext, "播放资源为空，请联系管理员添加！", Toast.LENGTH_LONG).show();
                });
            }
        }
    }

    private void clearCache() {
        new Thread(() -> {
            String photoCachePath = "/data/data/" + mContext.getPackageName() + "/media/photo/";
            String videoCachePath = "/data/data/" + mContext.getPackageName() + "/media/video/";
            try {
                mSharedPreferences.edit().clear().commit();
                File pcpFile = new File(photoCachePath);
                if (pcpFile.exists()) {
                    Log.d(TAG, "delete photo cache...");
                    for (File file : pcpFile.listFiles()) {
                        file.delete();
                    }
                }
                File vcpFile = new File(videoCachePath);
                if (vcpFile.exists()) {
                    Log.d(TAG, "delete video cache...");
                    for (File file : vcpFile.listFiles()) {
                        file.delete();
                    }
                }
                new Handler(Looper.getMainLooper()).postDelayed(() -> {
                    mWSClient.send("{\"type\":\"poster\"}");
                }, 200);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    public String readFile(String fileName) {
        String res = "";
        try {
            FileInputStream fin = openFileInput(fileName);
            int length = fin.available();
            byte[] buffer = new byte[length];
            fin.read(buffer);
            res = EncodingUtils.getString(buffer, "UTF-8");
            fin.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    private static class MyNetChangeListener implements NetWatchdog.NetChangeListener {
        @Override
        public void onWifiTo4G() {
        }

        @Override
        public void on4GToWifi() {
        }

        @Override
        public void onNetDisconnected() {
        }
    }

    final class EventWSClient extends WebSocketClient {
        private String initData;

        public EventWSClient(URI serverUri) {
            super(serverUri);
        }

        @Override
        public void onOpen(ServerHandshake handshakedata) {
            isWSSConnected = true;
            if (initData != null) {
                send(initData);
            }
        }

        @Override
        public void onMessage(String message) {
            Log.d(TAG, "wss msg:" + message);
            handleWSSMsg(message);
        }

        @Override
        public void onClose(int code, String reason, boolean remote) {
            Log.d(TAG, "server closed:" + reason);

        }

        @Override
        public void onError(Exception ex) {
            Log.d(TAG, "failed to connect to server:" + ex.getMessage());
            isWSSConnected = false;
            mHandler.postDelayed(() -> {
                if (!isWSSConnected && !isPlaying) {
                    tryToPlay();
                }
            }, 1000);
        }

        public void setInitData(String initData) {
            this.initData = initData;
        }
    }

    private class MyNetConnectedListener implements NetWatchdog.NetConnectedListener {
        @Override
        public void onReNetConnected(boolean isReconnect) {
            Log.d(TAG, "onReNetConnected:" + isReconnect);
            if (isReconnect)
                initEventWSS();
        }

        @Override
        public void onNetUnConnected() {

        }
    }
}